#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <time.h>

//a0 = 6- 4(raiz2)
//y0 = (raiz2) - 1

void inicializaY0(mpf_t *y0){
    mpf_t aux;

    mpf_init(aux);

    mpf_init_set_str(aux, "2", 10);
    mpf_sqrt(*y0, aux);

    mpf_init_set_str(aux, "1", 10);
    mpf_sub(*y0, *y0, aux);

    mpf_clears(aux, NULL);
}

void inicializaA0(mpf_t *a0){
    mpf_t aux;

    mpf_init(aux);

    mpf_init_set_str(aux, "2", 10);
    mpf_sqrt(*a0, aux);

    mpf_init_set_str(aux, "4", 10);
    mpf_mul(*a0, *a0, aux);

    mpf_init_set_str(aux, "6", 10);
    mpf_sub(*a0, aux, *a0);

    mpf_clears(aux, NULL);
}

void iteradorY(mpf_t *y){
    mpf_t aux;
    mpf_t aux2;

    mpf_init(aux);
    mpf_init(aux2);
    mpf_init_set(aux2, *y);

    //Numerador
    mpf_pow_ui (*y, *y, 4);

    mpf_init_set_str(aux, "1", 10);
    mpf_sub(*y, aux,*y);

    mpf_sqrt(*y, *y);
    mpf_sqrt(*y, *y);

    mpf_init_set_str(aux, "1", 10);
    mpf_sub(*y, aux,*y);

    //Denominador
    mpf_pow_ui (aux2, aux2, 4);

    mpf_init_set_str(aux, "1", 10);
    mpf_sub(aux2, aux,aux2);

    mpf_sqrt(aux2, aux2);
    mpf_sqrt(aux2, aux2);

    mpf_init_set_str(aux, "1", 10);
    mpf_add(aux2, aux, aux2);

    //Resultado Y(k+1)
    mpf_div(*y, *y, aux2);

    mpf_clears(aux, aux2, NULL);
}

void iteradorA(mpf_t *a, mpf_t y, int i){
    mpf_t aux;
    mpf_t aux2;

    mpf_init(aux);
    mpf_init(aux2);

    //Primeiro termo
    mpf_init_set_str(aux2, "1", 10);
    mpf_add(aux2, aux2, y);
    mpf_pow_ui (aux2, aux2, 4);

    mpf_mul(*a, *a, aux2);

    //Segundo termo
    mpf_init_set_str(aux, "1", 10);
    mpf_add(aux,aux,y);

    mpf_pow_ui (aux2, y, 2);
    mpf_add(aux,aux,aux2);

    mpf_mul(aux, y, aux);

    mpf_init_set_str(aux2, "2", 10);
    mpf_pow_ui (aux2, aux2, (2*i)+3);

    mpf_mul(aux, aux, aux2);

    //Resultado
    mpf_sub(*a, *a, aux);

    mpf_clears(aux, aux2, NULL);
}

int main(void){
    clock_t tInicio, tFim;
    tInicio = clock();

    int iteracoes, precisao = 33000000;
    mpf_t a0;
    mpf_t y0;
    mpf_t pi;
    mpf_t piAnterior;

    mpf_set_default_prec(precisao);

    mpf_init(a0);
    mpf_init(y0);
    mpf_init(pi);
    mpf_init(piAnterior);

    inicializaA0(&a0);
    inicializaY0(&y0);

    for(iteracoes = 0;;iteracoes++){
        mpf_init_set_str(pi, "1", 10);
        mpf_div(pi, pi, a0);

        if(iteracoes == 0)
            gmp_printf ("pi%d: %.70Ff\n", iteracoes, pi);
        else{
            if(!mpf_eq(piAnterior, pi, 33000000))
                gmp_printf ("pi%d: %.70Ff\n", iteracoes, pi);
            else
                break;
        }

        iteradorY(&y0);
        iteradorA(&a0, y0, iteracoes);

        mpf_set(piAnterior, pi);
    }

    tFim = clock();
    printf("\nTempo Decorrido:%ld ms\n\n", (tFim-tInicio)/(CLOCKS_PER_SEC/1000));
    /* free used memory */
    mpf_clears(a0, y0, pi, NULL);

    return EXIT_SUCCESS;
}
